/******************************************************
 * Copyright (c) 2012, LIJUN All rights reserved *
 ******************************************************/

/**
 * Util接口
 * @author carlli
 * @encode utf-8
 * @version 1.0
 * @data 2012.9.24
 * @modify
 * -------------------------------------------------------------------
 * 
 * -------------------------------------------------------------------
 * @usage
 * -------------------------------------------------------------------
 *
 * -------------------------------------------------------------------
 */
Smart.define("util", function(S){
    /**
     * 编码指定的字段
     * @param Object o 目标对象
     * @param String f 需要编码的字段名
     * @return Object o 转换后的对象
     */
    function EncodeField(o, f){
        if(f in o){
            o[f] = S.Request.encode(o[f].replace(/&amp;/gi, "&"));
        }
        
        return o;
    };
    /**
     * 解码指定的字段
     * @param Object o 目标对象
     * @param String f 需要解码的字段名
     * @return Object o 转换后的对象
     */
    function DecodeField(o, f){
        if(f in o){
            o[f] = S.Request.decode(o[f].replace(/&amp;/gi, "&"));
        }
        
        return o;
    };
    /**
     * 编码指定的字段
     * @param Object o 目标对象
     * @param Array fs 需要编码的字段集
     * @return Object o 转换后的对象
     */
    function EncodeFields(o, fs){
        for(var i = 0, len = fs.length; i < len; i++){
            o = EncodeField(o, fs[i]);
        }
        
        return o;
    };
    /**
     * 解码指定的字段
     * @param Object o 目标对象
     * @param Array f 需要解码的字段集
     * @return Object o 转换后的对象
     */
    function DecodeFields(o, fs){
        for(var i = 0, len = fs.length; i < len; i++){
            o = DecodeField(o, fs[i]);
        }
        
        return o;
    };
    /**
     * 获取模板数据
     * @param String tplName 模板名称
     * @return String tplData 模板数据
     */
    function GetTemplateData(tplName){
        var tplNode = null;
        var tplData = "";

        if(tplName && tplName.nodeType){//节点
            tplNode = tplName;
        }else{
            tplNode = (Y.Node.one('textarea[name="' + tplName + '"]') || Y.Node.one('script[name="' + tplName + '"]') || Y.Node.one(tplName));
        }

        if(tplNode){
            if("value" in tplNode){
                tplData = tplNode.value;
            }else{
                tplData = tplNode.innerHTML;
            }
        }

        return (tplData || "");
    };
    /**
     * 格式化模板数据
     * @param String tplName 模板名称
     * @param Object metaData 元数据
     * @param String preifx 模板数据前缀标识，默认为$
     * @return String str 格式化后的字符串
     */
    function Format(tplName, metaData, prefix){
        var tpl = GetTemplateData(tplName);
        var str = FormatData(tpl, metaData, prefix);

        return str;
    };
    /**
     * 格式化模板数据
     * @param String tpl 模板数据
     * @param Object metaData 元数据
     * @param String preifx 模板数据前缀标识，默认为$
     * @return String str 格式化后的字符串
     */
    function FormatData(tpl, metaData, prefix){
        var str = "";
        var reg = null;

        prefix = (undefined === prefix ? "\\$" : (prefix ? "\\" + prefix : "")) ;
        tpl = tpl || "";
        metaData = metaData || {};

        for(var key in metaData){
            if(metaData.hasOwnProperty(key)){
                reg = new RegExp(prefix + "\\!?\\{"+key+"\\}", "gm");
                str = tpl = tpl.replace(reg, S.Request.decode(metaData[key]));
                reg = null;
            }
        }

        str = (str || tpl);
        //----------------------------------
        reg = new RegExp(prefix + "\\!\\{[^\\{\\}]+\\}", "gm");
        str = str.replace(reg, "");
        reg = null;
        //----------------------------------
        return str;
    };
    /**
     * 匹配以prefix开头的字符串
     * @param String str 字符串
     * @param String prefix 匹配字符串
     * @param int offset 偏移值
     * @return Boolean 是否匹配 true/false
     */
    function StartsWith(str, prefix, offset){
        offset = typeof(offset) == "number" ? offset : 0;
        if (str.length >= (prefix.length + offset)){
            return (str.substr(offset, prefix.length) == prefix);
        }else{
            return false;
        }
    };
    /**
     * 匹配以suffix结尾的字符串
     * @param String str 字符串
     * @param String suffix 匹配字符串
     * @return Boolean 是否匹配 true/false
     */
    function EndsWith(str, suffix){
        if (str.length >= suffix.length){
            return (str.substr((str.length - suffix.length), suffix.length) == suffix);
        }else{
            return false;
        }
    };
    /**
     * 替换所有相匹配的字符或字符串
     * @param String str 字符串
     * @param String regexp 匹配表达式
     * @param String replacement 替换字符串
     * @return String tmp 替换后的字符串,如果没有找到匹配返回原字符串
     */
    function ReplaceAll(str, regexp, replacement){
        var pattern = new RegExp(regexp, "gm");
        var tmp = str.replace(pattern, replacement);
        pattern = null;
        return tmp;
    };
    /**
     * 替换匹配表达式第一次出现的内容
     * @param String str 字符串
     * @param String regexp 匹配表达式
     * @param String replacement 替换字符串
     * @return String tmp 替换后的字符串,如果没有找到匹配返回原字符串
     */
    function ReplaceFirst(str, regexp, replacement){
        var group = new RegExp("("+ regexp + ")", "gm").exec(str);
        var tmp = str;
        if (null != group){
            tmp = str.substring(0, group.index)
                .concat(replacement)
                .concat(str.substring(group.index+group[1].length));
        }
        group = null;
        return tmp;
    };
    /**
     * 去空字符
     * @param String str 字符串
     * @return String tmp 去空后的字符串
     */
    function Trim(str){
        var pattern = /[\s ]+/gmi;
        var tmp = str.replace(pattern, "");
        pattern = null;
        return tmp;
    };
    /**
     * 去左空字符
     * @param String str 字符串
     * @return String tmp 去空后的字符串
     */
    function LeftTrim(str){
        var pattern = /^[\s ]+/gmi;
        var tmp = str.replace(pattern, "");
        pattern = null;
        return tmp;
    };
    /**
     * 去右空字符
     * @param String str 字符串
     * @return String tmp 去空后的字符串
     */
    function RightTrim(str){
        var pattern = /[\s ]+$/gmi;
        var tmp = str.replace(pattern, "");
        pattern = null;
        return tmp;
    };
    /**
     * 去两边空字符
     * @param String str 字符串
     * @return String tmp 去空后的字符串
     */
    function BothTrim(str){
        return RightTrim((LeftTrim(str)));
    };
    /**
     * 返回实际长度,区分中英文
     * @param String str 字符串
     * @return long 字符串长度
     */
    function ActualLength(str){
        return str.replace(/[^\u0000-\u00FF]/gmi, "**").length;
    };
    /**
     * 填补字符串，前补齐指定位数
     * @param String str 字符串
     * @param char chr 填补字符
     * @param int bit 位数
     * @return String str 填补完后的字符串
     */
    function FillBefore(str, chr, bit){
        var len = str.length;
        var shift = bit - len + 1;
        var str = str;
        if(shift > 0){
            var a = new Array(shift);
            str = a.join(chr) + str;
            a = null;
        }
        return str;
    };
    /**
     * 填补字符串，前补齐指定位数
     * @param String str 字符串
     * @param char chr 填补字符
     * @param int bit 位数
     * @return String str 填补完后的字符串
     */
    function FillAfter(str, chr, bit){
        var len = str.length;
        var shift = bit - len + 1;
        var str = str;
        if(shift > 0){
            var a = new Array(shift);
            str = str + a.join(chr);
            a = null;
        }
        return str;
    };
    /**
     * 转换成货币格式
     * @param String str 字符串
     * @param int bit 小数位数
     * @return String str 返回转换后的字符串
     */
    function ToCurrency(str, bit){
        bit = bit || 2;
        var pattern = /^(\-?)(\d+)(\.\d+)?$/;
        var macher = pattern.exec(str);
        var sign = null != macher ? RegExp.$1 : "";
        var integer = null != macher ? RegExp.$2 : "0";
        var decimal = null != macher ? RegExp.$3 : ".00";
        var size = integer.length;
        var mod = size > 3 ? size % 3 : 0;
        var tmp = "";
        var start = 0 == mod ? "" : integer.substr(0, mod) + ",";
        var flag = 0;
        
        decimal = "" == decimal ? ".00" : decimal;
        decimal = (decimal.fillAfter(0, bit + 1)).substr(0, bit + 1);
        
        for(var i = mod; i < size; i++){
            tmp += integer.charAt(i);
            flag++;
            if(flag % 3 == 0 && i < size - 1){
                tmp += ",";
                flag = 0;
            }
        }
        pattern = null;
        return sign + start + tmp + decimal;
    };
    /**
     * clone对象
     * @param Object obj 对象
     * @param Boolean isDeep 是否为深度复制
     * @return Object o;
     */
    function CloneObject(obj, isDeep){
        var o = new Object();
        
        for(var key in obj){
            if(obj.hasOwnProperty(key)){
                if(isDeep){
                    if(obj[key] instanceof Object){
                        o[key] = obj[key].clone();
                    }else{
                        o[key] = obj[key];
                    }
                }else{
                    o[key] = obj[key];
                }
            }
        }
        return o;
    };
    /**
     * 格式化日期对象
     * @param Date oDate 日期对象
     * @param String fmt 格式 %y%M%d%h%m%s%i[%w%W%a%A]
     * @param Boolean isFill 是否补0
     * @return String dt 格式化的日期串
     */
    function DateFormat(oDate, fmt, isFill){
        var year = "" + oDate.getFullYear();
        var month = "" + (oDate.getMonth() + 1);
        var date = "" + oDate.getDate();
        var hour = "" + oDate.getHours();
        var minute = "" + oDate.getMinutes();
        var second = "" + oDate.getSeconds();
        var miSec = "" + oDate.getMilliseconds();
        var day = oDate.getDay();
        var cn_weeks = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
        var cn_weeks_abbr = ["日", "一", "二", "三", "四", "五", "六"];
        var en_weeks = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        var en_weeks_abbr = ["Sun.", "Mon.", "Tues.", "Wed.", "Thur.", "Fri.", "Sat."];
        
        isFill = typeof(isFill) == "boolean" ? isFill : true;
        fmt = fmt || "%y%M%d%h%m%s%i %w";
        fmt = fmt.replace("%y", year);
        fmt = fmt.replace("%M", isFill ? FillBefore(month, "0", 2) : month);
        fmt = fmt.replace("%d", isFill ? FillBefore(date, "0", 2) : date);
        fmt = fmt.replace("%h", isFill ? FillBefore(hour, "0", 2) : hour);
        fmt = fmt.replace("%m", isFill ? FillBefore(minute, "0", 2) : minute);
        fmt = fmt.replace("%s", isFill ? FillBefore(second, "0", 2) : second);
        fmt = fmt.replace("%i", isFill ? FillBefore(miSec, "0", 3) : miSec);
        fmt = fmt.replace("%w", cn_weeks[day]);
        fmt = fmt.replace("%W", en_weeks[day]);
        fmt = fmt.replace("%a", cn_weeks_abbr[day]);
        fmt = fmt.replace("%A", en_weeks_abbr[day]);
        
        return fmt;
    };
    /**
     * 将字符串解析成日期对象
     * @param String str 需要解析的字符串
     * @param String fmt 日期格式
     * @return Date date 日期对象
     */
    function ParseDate(str, fmt){
        return ValidDate(str, fmt).date;
    };
    /**
     * 校验字符串是否为日期格式
     * @param String str 需要校验的字符串
     * @param String fmt 日期格式
     * @return Object {Boolean isValid, Date date} 返回校验后的布尔值和日期对象
     */
    function ValidDate(str, fmt){
        var tmp = "";
        fmt = fmt || "%y%M%d%h%m%s";
        tmp = fmt;
        fmt = fmt.replace("%y", "(\\d{4})");
        fmt = fmt.replace("%M", "(\\d{1,2})");
        fmt = fmt.replace("%d", "(\\d{1,2})");
        fmt = fmt.replace("%h", "(\\d{1,2})");
        fmt = fmt.replace("%m", "(\\d{1,2})");
        fmt = fmt.replace("%s", "(\\d{1,2})");
        fmt = fmt.replace("%i", "(\\d{1,3})");
        fmt = fmt.replace("%w", "(星期[日|一|二|三|四|五|六])");
        fmt = fmt.replace("%W", "(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)");
        fmt = fmt.replace("%a", "(日|一|二|三|四|五|六)");
        fmt = fmt.replace("%A", "(Sun\\.|Mon\\.|Tues\\.|Wed\\.|Thur\\.|Fri\\.|Sat\\.)");
        var regExp = new RegExp("^" + fmt + "$");
        var group = regExp.exec(str);
        var _year, _month, _date, _hour, _minute, _second, _millisecond;
        var yIndex = getIndex("y", tmp);
        var MIndex = getIndex("M", tmp);
        var dIndex = getIndex("d", tmp);
        var hIndex = getIndex("h", tmp);
        var mIndex = getIndex("m", tmp);
        var sIndex = getIndex("s", tmp);
        var iIndex = getIndex("i", tmp);
        var isUndefined = (undefined === yIndex
                        && undefined === MIndex
                        && undefined === dIndex
                        && undefined === hIndex
                        && undefined === mIndex
                        && undefined === sIndex
                        && undefined === iIndex);
        var _is = false;
        var d = new Date();
        if (null != group){
            group.shift();
            _year = undefined === yIndex ? d.getFullYear() : parse(group[yIndex]);
            _month = undefined === MIndex ? d.getMonth() : parse(group[MIndex])-1;
            _date = undefined === dIndex ? d.getDate() : parse(group[dIndex]);
            _hour = undefined === hIndex ? d.getHours() : parse(group[hIndex]);
            _minute = undefined === mIndex ? d.getMinutes() : parse(group[mIndex]);
            _second = undefined === sIndex ? d.getSeconds() : parse(group[sIndex]);
            _millisecond = undefined === iIndex ? d.getMilliseconds() : parse(group[iIndex]);
            d = new Date(_year, _month, _date, _hour, _minute, _second, _millisecond);
            _is = (false === isUndefined) && ((d.getFullYear()===_year)
                && (d.getMonth() === _month)
                && (d.getDate() === _date)
                && (d.getHours() === _hour)
                && (d.getMinutes() === _minute)
                && (d.getSeconds() === _second)
                && (d.getMilliseconds() === _millisecond));
        }
        function parse(v){
            return typeof(v) == "undefined" ? 0 : parseInt(v, 10);
        }
        function getIndex(flag, fmt){
            var tmp = fmt.replace(/[^%yMdhmsi]+/g, "");
            var arr = tmp.split("%");
            var size = arr.length;
            for(var i = 1; i < size; i++){
                if(arr[i] == flag){
                    return (i - 1);
                }
            }
            return undefined;
        }
        return {isValid : _is, date : d};
    };
    /**
     * 判断是否是闰年
     * @param Date oDate 日期对象
     * @return Object o {Boolean isLeapYear, int days, int yearDays, int monthDays} 集合(是否是闰年，各月份的天数集，当前月的天数)
     */
    function LeapYear(oDate){
        var _days = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
        var _is = false;
        var _d = 365;
        if ((oDate.getFullYear() % 4 == 0 && oDate.getFullYear() % 100 != 0) || oDate.getFullYear() % 400 == 0){
            _days.splice(1,1,29);
            _is = true;
            _d = 366;
        }else{
            _days.splice(1,1,28);
            _is = false;
            _d = 365;
        }
        return {isLeapYear:_is, days:_days, yearDays:_d, monthDays:_days[oDate.getMonth()]};
    };
    /**
     * 计算date与oDate之间的差值
     * @param char interval 间隔参数
     *        y 年
     *        q 季度
     *        n 月
     *        d 日
     *        w 周
     *        h 小时
     *        m 分钟
     *        s 秒
     *        i 毫秒
     * @param Date date 比较日期
     * @param Date oDate 
     * @return long diff 差值
     */
    function DateDiff(interval, date, oDate){
        var diff = 0;
        switch(interval){
            case 'y':
                diff = date.getFullYear() - oDate.getFullYear();
                break;
            case 'q':
                diff = ((date.getMonth() + 1) + ((date.getFullYear() - oDate.getFullYear()) * 12) - (oDate.getMonth() + 1)) / 3;
                break;
            case 'n':
                diff = (date.getMonth() + 1) + ((date.getFullYear() - oDate.getFullYear()) * 12) - (oDate.getMonth() + 1);
                break;
            case 'd':
                diff = (date - oDate) / 86400000;
                break;
            case 'w':
                diff = (date - oDate) / (86400000 * 7);
                break;
            case 'h':
                diff = (date - oDate) / 3600000;
                break;
            case 'm':
                diff = (date - oDate) / 60000;
                break;
            case 's':
                diff = (date - oDate) / 1000;
                break;
            case 'i':
                diff = date.getTime() - oDate.getTime();
                break;
            default:
                diff = date.getTime() - oDate.getTime();
                break;
        }
        return diff;
    };
    /**
     * 日期相加
     * @param char interval 间隔参数
     *        y 年
     *        q 季度
     *        n 月
     *        d 日
     *        w 周
     *        h 小时
     *        m 分钟
     *        s 秒
     *        i 毫秒
     * @param Date oDate 日期
     * @param int num 差值
     * @return Date newDate 相加后的日期
     */
    function DateAdd(interval, oDate, num){
        switch(interval){
            case 'y':
                oDate.setFullYear(oDate.getFullYear() + num);
                break;
            case 'q':
                oDate.setMonth(oDate.getMonth() + (num * 3));
                break;
            case 'n':
                oDate.setMonth(oDate.getMonth() + num);
                break;
            case 'd':
                oDate.setDate(oDate.getDate() + num);
                break;
            case 'w':
                oDate.setDate(oDate.getDate() + (num * 7));
                break;
            case 'h':
                oDate.setHours(oDate.getHours() + num);
                break;
            case 'm':
                oDate.setMinutes(oDate.getMinutes() + num);
                break;
            case 's':
                oDate.setSeconds(oDate.getSeconds() + num);
                break;
            case 'i':
                oDate.setMilliseconds(oDate.getMilliseconds() + num);
                break;
            default:
                oDate.setMilliseconds(oDate.getMilliseconds() + num);
                break;
        }
        return oDate;
    };
    /**
     * 获取时间戳
     */
    function GetTimeStamp(){
        return (new Date()).getTime();
    };
    /**
     * 获取文档大小
     * @return Object {int width, int height}
     */
    function GetDocumentSize(){
        var viewport = GetViewportSize();
        var _w = 0;
        var _h = 0;
        if(document.documentElement && document.documentElement.scrollWidth)
        {
            _w = document.documentElement.scrollWidth;
            _h = document.documentElement.scrollHeight;
        }
        else if(document.body && document.body.scrollWidth)
        {
            _w = document.body.scrollWidth;
            _h = document.body.scrollHeight;
        }
        else
        {
            _w = viewport.width;
            _h = viewport.height;
        }
        return {width:_w, height:_h};
    };
    /**
     * 获取视窗大小
     * @return Object {int width, int height}
     */
    function GetViewportSize(){
        var _w = 0;
        var _h = 0;
        if(window.innerWidth)
        {
            _w = window.innerWidth;
            _h = window.innerHeight;
        }
        else if(document.documentElement && document.documentElement.clientWidth)
        {
            _w = document.documentElement.clientWidth;
            _h = document.documentElement.clientHeight;
        }
        else if(document.body && document.body.clientWidth)
        {
            _w = document.body.clientWidth;
            _h = document.body.clientHeight;
        }
        return {width:_w, height:_h};
    };
    /**
     * 获取滚动条的位置
     * @return Object {int left, int top}
     */
    function GetScrollPosition(){
        var _l = 0;
        var _t = 0;
        if(window.innerWidth)
        {
            _l = window.pageXOffset;
            _t = window.pageYOffset;
        }
        else if(document.documentElement && document.documentElement.clientWidth)
        {
            _l = document.documentElement.scrollLeft;
            _t = document.documentElement.scrollTop;
        }
        else if(document.body && document.body.clientWidth)
        {
            _l = document.body.scrollLeft;
            _t = document.body.scrollTop;
        }
        return {left:_l, top:_t};
    };
    /**
     * 获取屏幕大小
     * @return Object {int width, int height, int offsetTop, int offsetLeft}
     */
    function GetScreenSize(){
        var _w = window.screen.width;
        var _h = window.screen.height;
        var _t = window.screenTop || window.screenX;
        var _l = window.screenLeft || window.screenY;
        return {width:_w, height:_h, offsetTop:_t, offsetLeft:_l};
    };
    /**
     * 获取滚动条大小
     * @member width 滚动条宽
     * @member height 滚动条高
     * @return 滚动条大小
     */
    function GetScrollbarSize(){
        var inner = document.createElement("p");
        var outer = document.createElement("div");
        inner.style.width = "100%";
        inner.style.height = "200px";
        outer.style.position = "absolute";
        outer.style.top = "0px";
        outer.style.left = "0px";
        outer.style.visibility = "hidden";
        outer.style.width = "200px";
        outer.style.height = "150px";
        outer.style.overflow = "hidden";
        S.Node.append(inner, outer);
        S.Node.append(outer, document.body);
        var w1 = inner.offsetWidth;
        var h1 = inner.offsetHeight;
        outer.style.overflow = "scroll";
        var w2 = inner.offsetWidth;
        var h2 = inner.offsetHeight;
        if(w1 == w2){
            w2 = outer.clientWidth;
        }
        if(h1 == h2){
            h2 = outer.clientWidth;
        }
        S.Node.remove(outer, document.body);
        return {width : (w1 - w2), height : (h1 - h2)};
    };
    
    var __util = {
        format : Format,
        formatData : FormatData,
        encodeField : EncodeField,
        encodeFields : EncodeFields,
        decodeField : DecodeField,
        decodeFields : DecodeFields,
        startsWith : StartsWith,
        endsWith : EndsWith,
        replaceAll : ReplaceAll,
        replaceFirst : ReplaceFirst,
        trim : Trim,
        leftTrim : LeftTrim,
        rightTrim : RightTrim,
        bothTrim : BothTrim,
        actualLength : ActualLength,
        fillBefore : FillBefore,
        fillAfter : FillAfter,
        toCurrency : ToCurrency,
        cloneObject : CloneObject,
        dateFormat : DateFormat,
        parseDate : ParseDate,
        validDate : ValidDate,
        leapYear : LeapYear,
        dateDiff : DateDiff,
        dateAdd : DateAdd,
        getTimeStamp : GetTimeStamp,
        getDocumentSize : GetDocumentSize,
        getViewportSize : GetViewportSize,
        getScrollPosition : GetScrollPosition,
        getScreenSize : GetScreenSize,
        getScrollbarSize : GetScrollbarSize
    };
    S.source("Util", __util);
});